﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Management;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Microsoft.Win32;
using YAWD.BL.Providers;
using YAWD.Data;
using YAWD.Properties;

namespace YAWD.Utils
{
    internal static class NativeMethods
    {
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        internal static extern Int32 SystemParametersInfo(UInt32 uiAction, UInt32 uiParam, String pvParam, UInt32 fWinIni);

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool RegisterHotKey(IntPtr hWnd, int id, ModifierKeys fsModifiers, System.Windows.Forms.Keys vk);

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);

    }

    static class Util
    {
        private const UInt32 SpiSetdeskwallpaper = 20;
        private const UInt32 SpifUpdateinifile = 0x1;
        private const UInt32 SpifSendwininichange = 0x02;

        const string ConnectionString = "K2oXHV01QxUmoZhYT+VJ+5Ponq+s5YElGKKVvaAFa9kc4Wf3Z/JLyUCszcjoCTBxW4OwOfLHTllLa28kIWnxB5KGwFKn9ouW5uFn8yAZIc2GNm3qXkWjtHHagZbVStsg0PXjQw/VX6B7P875Rr7yucawFjTISERunF0ZGzv80iQbA6z66k7ML+S1BvlDcHOy4c23TFL96LIgrx9nfKVO/NH6F4/tZATJuf4k5qlYhnVkvSBbhWJSlAxW/mcpVRex";
        const string ConnectionStringNews = "K2oXHV01QxUmoZhYT+VJ+5Ponq+s5YElGKKVvaAFa9kc4Wf3Z/JLyUCszcjoCTBxW4OwOfLHTllLa28kIWnxB1PARFfZfqMHxCUaKaTOSzG7JfNX0McVigA4OudJb5cndZVmsOwBpgArP9MJ/G1qXVHDj5ZriJ5b/NHrsF2C0w/8tPFFss2I5OMdNDtajOXOUjxtBoAY05E4dMH1LlbB9HDPJDMBNdL050Z3UhMQX+li2KhlWdN8YScc0p39cP51";


        public static void AddToStartup(string name, string path)
        {
            RemoveToStartup(name);
            RegistryKey key = Registry.LocalMachine.OpenSubKey(
                @"Software\Microsoft\Windows\CurrentVersion\Run", true);

            if (key != null)
                key.SetValue(name, @"""" + path + @"""", RegistryValueKind.String);
        }

        public static bool ChangeWallPaper(string path)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(path)) return false;
                WallPaperLayout layout;
                Image wallPaper = Image.FromFile(path);
                decimal aspctRation = wallPaper.Width / (decimal)wallPaper.Height;
                decimal desktopRatio = (decimal)SystemParameters.PrimaryScreenWidth / (decimal)SystemParameters.PrimaryScreenHeight;

                if (aspctRation < desktopRatio)
                    layout = WallPaperLayout.Fit;
                else
                    layout = WallPaperLayout.Stretched;

                if (Directory.Exists(@".\Temp") == false)
                    Directory.CreateDirectory(@".\Temp");

                string appPath = Assembly.GetExecutingAssembly().Location.Replace("YAWD.exe", "");

                appPath = Path.Combine(appPath, @"Temp\temp.bmp");
                wallPaper.Save(appPath, System.Drawing.Imaging.ImageFormat.Bmp);
                wallPaper.Dispose();

                RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);

                switch (layout)
                {
                    case WallPaperLayout.Tiled:
                        if (key != null)
                        {
                            key.SetValue(@"WallpaperStyle", 1.ToString(CultureInfo.InvariantCulture));
                            key.SetValue(@"TileWallpaper", 10.ToString(CultureInfo.InvariantCulture));
                        }
                        break;
                    case WallPaperLayout.Centered:
                        if (key != null)
                        {
                            key.SetValue(@"WallpaperStyle", 1.ToString(CultureInfo.InvariantCulture));
                            key.SetValue(@"TileWallpaper", 0.ToString(CultureInfo.InvariantCulture));
                        }
                        break;
                    case WallPaperLayout.Stretched:
                        if (key != null)
                        {
                            key.SetValue(@"WallpaperStyle", 2.ToString(CultureInfo.InvariantCulture));
                            key.SetValue(@"TileWallpaper", 0.ToString(CultureInfo.InvariantCulture));
                        }
                        break;
                    case WallPaperLayout.Fill:
                        if (key != null)
                        {
                            key.SetValue(@"WallpaperStyle", 10.ToString(CultureInfo.InvariantCulture));
                            key.SetValue(@"TileWallpaper", 0.ToString(CultureInfo.InvariantCulture));
                        }
                        break;
                    case WallPaperLayout.Fit:
                        if (key != null)
                        {
                            key.SetValue(@"WallpaperStyle", 6.ToString(CultureInfo.InvariantCulture));
                            key.SetValue(@"TileWallpaper", 0.ToString(CultureInfo.InvariantCulture));
                        }
                        break;
                }

                NativeMethods.SystemParametersInfo(SpiSetdeskwallpaper, 0, appPath, SpifUpdateinifile | SpifSendwininichange);
                Settings settings = Settings.Default;
                settings.CurrentWallPaper = path;
                settings.Save();
                return true;
            }
            catch (Exception ex)
            {
                LogException(ex, path);
                return false;
            }

        }

        public static string GetExternalIp()
        {
            const string whatIsMyIp = "http://whatismyipaddress.com/";
            try
            {
                string ipaddr = string.Empty;
                string results = GetHtmlPage(whatIsMyIp, null);
                if (string.IsNullOrWhiteSpace(results) == false)
                {
                    const string strParsing = @"<!-- do not script -->";
                    int intTemp = results.IndexOf(strParsing, StringComparison.Ordinal);
                    if (intTemp > -1)
                    {
                        results = results.Substring(intTemp + strParsing.Length);
                        ipaddr = results.Substring(0, results.IndexOf(strParsing, StringComparison.Ordinal)).Trim();
                    }
                }
                return ipaddr;
            }
            catch
            {
                return null;
            }
        }
        public static TimeSpan GetDuration(double value, Units units)
        {
            switch (units)
            {
                case Units.Minutes:
                    return TimeSpan.FromMinutes(value);
                case Units.Hours:
                    return TimeSpan.FromHours(value);
                case Units.Days:
                    return TimeSpan.FromDays(value);
                case Units.Week:
                    return TimeSpan.FromDays(value * 7);
                default:
                    return TimeSpan.Zero;
            }
        }
        public static TimeSpan GetDurationUpdate(double value, UpdateUnits units)
        {
            switch (units)
            {
                case UpdateUnits.Hours:
                    return TimeSpan.FromHours(value);
                case UpdateUnits.Days:
                    return TimeSpan.FromDays(value);
                case UpdateUnits.Week:
                    return TimeSpan.FromDays(value * 7);
                default:
                    return TimeSpan.Zero;
            }
        }
        public static string GetHtmlPage(string strUrl, Encoding objEncoding, string referer="")
        {
            try
            {
                string strResults = string.Empty;

                if (string.IsNullOrEmpty(strUrl) == false)
                {
                    WebClient objService = new WebClient();
                    strUrl = strUrl.Replace(" ", "%20");
                    strUrl = strUrl.Replace("&amp;", "&");

                    WebProxy proxy = GetProxy();
                    if (proxy != null)
                        objService.Proxy = proxy;

                    objService.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
                    objService.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.5");
                    objService.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1");

                    if (string.IsNullOrWhiteSpace(referer) == false)
                        objService.Headers.Add("Referer", referer);

                    if (objEncoding == null)
                        objEncoding = Encoding.Default;

                    objService.Encoding = objEncoding;

                    using (MemoryStream memoryStream = new MemoryStream(objService.DownloadData(strUrl)))
                    {

                        switch (objService.ResponseHeaders[HttpResponseHeader.ContentEncoding])
                        {
                            case "gzip":
                                strResults = new StreamReader(new GZipStream(memoryStream, CompressionMode.Decompress), objEncoding).ReadToEnd();
                                break;
                            case "deflate":
                                strResults = new StreamReader(new DeflateStream(memoryStream, CompressionMode.Decompress), objEncoding).ReadToEnd();
                                break;
                            default:
                                strResults = new StreamReader(memoryStream, objEncoding).ReadToEnd();
                                break;
                        }
                    }


                    //Replace HTML entity references so that we can load into XElement
                    strResults = strResults.Replace("&nbsp;", "");
                    strResults = strResults.Replace("&", "&amp;");
                }

                return strResults;

            }
            catch (Exception)
            {
                return null;
            }
        }
        public static int GetImage(string strUrl, string referer, string folderName, string filename, bool useGzip)
        {

            try
            {
                if (string.IsNullOrWhiteSpace(strUrl)) return 0;

                strUrl = strUrl.Replace(" ", "%20");
                if (strUrl.EndsWith(".js", true, CultureInfo.InvariantCulture) == false)
                {
                    WebClient objService = new WebClient();

                    WebProxy proxy = GetProxy();
                    if (proxy != null)
                        objService.Proxy = proxy;

                    if (useGzip == true)
                        objService.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");

                    objService.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1");

                    if (string.IsNullOrWhiteSpace(referer) == false)
                        objService.Headers.Add("Referer", referer);

                    Settings settings = Settings.Default;
                    string initPath;
                    if (string.IsNullOrWhiteSpace(settings.WallPapersPath))
                        initPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                    else
                        initPath = settings.WallPapersPath;


                    string folderPath = Path.Combine(initPath, folderName);

                    if (Directory.Exists(folderPath) == false)
                        Directory.CreateDirectory(folderPath);

                    string filepath = Path.Combine(folderPath, filename);

                    if (File.Exists(filepath) == false)
                    {
                        objService.DownloadFile(strUrl.Trim(), filepath);
                        return 1;
                    }
                }

                return 0;

            }
            catch (WebException webex)
            {
                if (webex.Message.Contains("404") == false)
                    LogException(webex, strUrl);

                return 0;
            }
            catch (Exception ex)
            {
                LogException(ex, strUrl);
                return 0;
            }
        }
        public static News GetLatestNews(int id)
        {
            SqlConnection connection = null;
            try
            {
                News newsResults = null;
                connection = new SqlConnection(Uncrypte(ConnectionStringNews));
                string query = string.Format("SELECT TOP 1 Id,Title,Body,Link,Ip,BinaryVersion FROM News where id > {0} AND AppName='{1}'", id.ToString(CultureInfo.InvariantCulture), "Yawd");
                connection.Open();
                SqlDataReader newsReader = new SqlCommand(query, connection).ExecuteReader();


                if (newsReader.HasRows == true)
                {
                    newsReader.Read();
                    newsResults = new News();
                    newsResults.Id = newsReader.GetInt32(0);
                    newsResults.Title = newsReader.GetString(1);
                    newsResults.Body = newsReader.GetString(2);

                    if (newsReader[3] != DBNull.Value)
                        newsResults.Link = newsReader.GetString(3);

                    if (newsReader[4] != DBNull.Value)
                        newsResults.Ip = newsReader.GetString(4);
                }

                connection.Close();
                return newsResults;
            }
            catch (Exception)
            {
                if (connection != null)
                    connection.Close();

                return null;

            }
        }
        private static WebProxy GetProxy()
        {
            if (Convert.ToBoolean(ConfigurationManager.AppSettings["UseProxy"]) == true)
            {
                WebProxy proxy = new WebProxy(ConfigurationManager.AppSettings["ProxyIp"].ToString(CultureInfo.InvariantCulture) + ":" + ConfigurationManager.AppSettings["ProxyPort"], false, null);
                proxy.Credentials = new NetworkCredential(ConfigurationManager.AppSettings["ProxyLogin"], ConfigurationManager.AppSettings["ProxyPwd"]);
                return proxy;
            }
            else
                return null;
        }

        private static string GetValue(KeyValueConfigurationCollection settings, string key)
        {
            if (settings[key] != null)
                return settings[key].Value;
            else
                return null;
        }
        public static IList<string> LoadImage(Providers providerName, string initialPath)
        {
            if (string.IsNullOrWhiteSpace(initialPath)) return null;

            DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(initialPath, providerName.ToString()));
            List<string> wallPapers = new List<string>();
            if (directoryInfo.Exists == true)
                foreach (FileInfo item in directoryInfo.GetFiles().OrderByDescending(t => t.LastWriteTime).ToList())
                {
                    try
                    {
                        wallPapers.Add(item.FullName);
                    }
                    catch (Exception)
                    { }
                }
            return wallPapers;
        }
        public static void LogException(Exception ex)
        {
            Task.Factory.StartNew(() => LogExceptionAsync(ex, string.Empty));

            string strName = "Errors" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + ".log";
            if (File.Exists(strName) == false)
            {
                StreamWriter objTemp = File.CreateText(strName);
                objTemp.Close();
            }

            StreamWriter sw =
                File.AppendText("Errors" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + ".log");

            sw.WriteLine("Message :" + ex.Message);
            sw.WriteLine("Source :" + ex.Source);
            if (ex.TargetSite != null) sw.WriteLine("TargetSite :" + ex.TargetSite);
            if (ex.InnerException != null)
                sw.WriteLine("InnerException :" + ex.InnerException);

            sw.WriteLine("StackTrace :" + ex.StackTrace);
            sw.WriteLine("------------------------------------------------------------");
            sw.Flush();
            sw.Close();
        }
        public static void LogException(Exception ex, string strParams)
        {
            Task.Factory.StartNew(() => LogExceptionAsync(ex, strParams));

            string strName = "Errors" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + ".log";
            if (File.Exists(strName) == false)
            {
                StreamWriter objTemp = File.CreateText(strName);
                objTemp.Close();
            }

            StreamWriter sw =
                File.AppendText("Errors" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + ".log");

            sw.WriteLine("Params :" + strParams);
            sw.WriteLine("Message :" + ex.Message);
            sw.WriteLine("Source :" + ex.Source);
            if (ex.TargetSite != null) sw.WriteLine("TargetSite :" + ex.TargetSite);
            if (ex.InnerException != null)
                sw.WriteLine("InnerException :" + ex.InnerException);

            sw.WriteLine("StackTrace :" + ex.StackTrace);
            sw.WriteLine("------------------------------------------------------------");

            sw.Flush();
            sw.Close();
        }
        private static void LogExceptionAsync(Exception ex, string param)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(((App)Application.Current).Ip) == false)
                {
                    SqlConnection connection = new SqlConnection(Uncrypte(ConnectionString));
                    string query = string.Format(@"INSERT INTO Exception (AppName,Message,Source,TargetSite,InnerException,StackTrace,Ip,BinaryVersion) VALUES('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}')"
                                                        , "Yawd", ex.Message + Environment.NewLine + "Param :" + param, ex.Source, ex.TargetSite,
                                                        ex.InnerException, ex.StackTrace, ((App)Application.Current).Ip, Assembly.GetExecutingAssembly().GetName().Version);

                    connection.Open();
                    new SqlCommand(query, connection).ExecuteNonQuery();
                    connection.Close();
                }

            }
            catch (Exception)
            {

            }

        }

        public static string ParseConnectionString(string strConnectionString)
        {
            try
            {
                if (string.IsNullOrEmpty(strConnectionString))
                    return string.Empty;

                string strFilePath = strConnectionString.Replace(@"Data Source=", "");
                strFilePath = strFilePath.Replace('"', ' ').Trim();

                return strFilePath;
            }
            catch (Exception ex)
            {
                LogException(ex);
                return string.Empty;
            }
        }

        public static IProvider ReadProviderSettings(IProvider provider)
        {
            ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
            configFileMap.ExeConfigFilename = string.Format(@".\BL\Providers\{0}\{0}.config", provider.GetType().Name);
            Configuration configFile = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
            AppSettingsSection setting = (AppSettingsSection)configFile.GetSection("appSettings");

            provider.URL = GetValue(setting.Settings, "URL");
            provider.FirstImage = GetValue(setting.Settings, "FirstImage");
            provider.LastDwImage = GetValue(setting.Settings, "LastDwImage");
            provider.LastId = GetValue(setting.Settings, "LastId");

            DateTime lastUpdate;
            if (DateTime.TryParse(GetValue(setting.Settings, "LastUpdated"), out lastUpdate))
                provider.LastUpdated = lastUpdate;

            return provider;
        }
        public static void RemoveToStartup(string name)
        {
            RegistryKey key = Registry.CurrentUser.OpenSubKey(
                @"Software\Microsoft\Windows\CurrentVersion\Run", true);

            if (key != null)
                key.DeleteValue(name, false);
        }

        public static void SaveToConfigFile(string strKey, string strValue, IProvider provider)
        {
            ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
            configFileMap.ExeConfigFilename = string.Format(@".\BL\Providers\{0}\{0}.config", provider.GetType().Name);
            Configuration objConfig = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
            AppSettingsSection objAppsettings = (AppSettingsSection)objConfig.GetSection("appSettings");

            try
            {

                if (objAppsettings != null)
                    objAppsettings.Settings[strKey].Value = strValue;
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
            finally
            {
                objConfig.Save();
            }
        }

        public static Version GetAppVersion()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            Version currentVersion = assembly.GetName().Version;
            return currentVersion;
        }

        private static string GetOsName()
        {

            const string osQuery = "SELECT * FROM Win32_OperatingSystem";
            string strName = string.Empty;
            ManagementObjectSearcher osSearcher = new ManagementObjectSearcher(osQuery);
            foreach (ManagementObject info in osSearcher.Get())
            {
                strName = info.Properties["Caption"].Value.ToString().Trim();
            }
            return strName;

        }

        public static void NotifyEvent(string strUsage)
        {
            SqlConnection connection = null;
            try
            {
                if (string.IsNullOrWhiteSpace(((App)Application.Current).Ip) == false)
                {

                    connection = new SqlConnection(Uncrypte(ConnectionString));
                    string query = string.Format(@"INSERT INTO Usages (AppName,BinaryVersion,Event,OSName,OSLanguage,Ip) VALUES('{0}','{1}','{2}','{3}','{4}','{5}')",
                                                                       "Yawd", Assembly.GetExecutingAssembly().GetName().Version, strUsage, GetOsName(), CultureInfo.CurrentCulture.DisplayName,
                                                                        ((App)Application.Current).Ip);
                    connection.Open();
                    new SqlCommand(query, connection).ExecuteNonQuery();
                    connection.Close();
                    connection.Dispose();
                }
            }
            catch (Exception)
            {
                if (connection != null)
                {
                    connection.Close();
                    connection.Dispose();
                }
            }
        }

        private static string Uncrypte(string tobeDecrypted)
        {
            byte[] encryptedTextBytes = Convert.FromBase64String(tobeDecrypted);
            MemoryStream ms = new MemoryStream();
            SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
            byte[] rgbIv = Encoding.ASCII.GetBytes("ryojvlzmdalyglrj");
            byte[] key = Encoding.ASCII.GetBytes("hcxilkqbbhczfeultgbskdmaunivmfuo");

            CryptoStream cs = new CryptoStream(ms, rijn.CreateDecryptor(key, rgbIv),
            CryptoStreamMode.Write);

            cs.Write(encryptedTextBytes, 0, encryptedTextBytes.Length);
            cs.Close();
            return Encoding.UTF8.GetString(ms.ToArray());
        }

    }
}
